package com.meiqia.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.meiqia.common.asserts.Asserts;
import com.meiqia.common.constant.Constants;
import com.meiqia.common.util.CodecUtils;
import com.meiqia.common.util.StringUtils;
import com.meiqia.user.entity.Balance;
import com.meiqia.user.entity.BalanceTrade;
import com.meiqia.user.mapper.BalanceMapper;
import com.meiqia.user.service.BalanceService;
import com.meiqia.user.service.BalanceTradeService;
import com.meiqia.user.struct.PageResult;
import com.meiqia.user.vo.SearchVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * <p>
 * 用户余额 服务实现类
 * </p>
 *
 * @author lightman
 * @since 2020-12-08
 */
@Service
public class BalanceServiceImpl extends ServiceImpl<BalanceMapper, Balance> implements BalanceService {

    @Autowired
    private BalanceTradeService balanceTradeService;

    @Override
    public PageResult<Balance> page(Integer currPage, Integer pageSize, SearchVO vo) {
        // 分页
        Page<Balance> balancePage = new Page<>(currPage, pageSize);

        // 条件查询
        QueryWrapper<Balance> wrapper = new QueryWrapper<>();

        if (Objects.nonNull(vo)) {
            String keyWord = vo.getKeyWord();
            if (StringUtils.isNotEmpty(keyWord)) {
                wrapper.like("name", keyWord);
            }
        }
        balancePage = page(balancePage, wrapper);
        return PageResult.of(balancePage.getRecords(), balancePage.getTotal());
    }

    @Override
    public boolean saveBalance(Balance balance) {
        return save(balance);
    }


    @Override
    public boolean updateBalance(Balance balance) {
        return updateById(balance);
    }

    @Override
    public boolean delById(Long id) {
        return removeById(id);
    }

    @Override
    public boolean delByIds(List<Long> ids) {
        return removeByIds(ids);
    }

    // 初始化余额
    private Balance Init(Long userId) {
        // 创建交易明细对象
        BalanceTrade balanceTrade = new BalanceTrade();

        // 初始化所属用户
        balanceTrade.setUserId(userId);
        // 初始化订单编号
        balanceTrade.setOrderNo(Long.toString(System.currentTimeMillis()));
        // 初始化借贷 我们让他初始也就是重置0元, 0消费,1充值
        balanceTrade.setDebit(1);
        // 初始要发生的金额
        balanceTrade.setAmount(Constants.Balance.bigDecimal);
        // 初始化所剩余额
        balanceTrade.setBalance(Constants.Balance.bigDecimal);
        // 初始化备注信息
        balanceTrade.setRemark("用户开户");
        // 初始化最后发生时间
        balanceTrade.setCreated(new Date());
        balanceTradeService.save(balanceTrade);

        // 创建余额对象
        Balance balance = new Balance();
        // 初始化信息
        balance.setUserId(userId);
        balance.setAmounts(Constants.Balance.bigDecimal);
        // 初始化校验码
        String checkCode = getCheckCode(balanceTrade.getOrderNo(),
                balanceTrade.getDebit(),
                balanceTrade.getAmount(),
                balanceTrade.getBalance(),
                balanceTrade.getCreated());
        // 余额变动校验码
        balance.setChecksum(checkCode);
        // 锁定资金账户 1:true 0:false
        balance.setLocked(0);
        save(balance);

        return balance;
    }

    // 加密
    private String getCheckCode(String orderNo,
                                Integer debit,
                                BigDecimal amount,
                                BigDecimal balance,
                                Date created) {
        // 创建 stringBuffer对象
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append(orderNo).append(debit).append(amount).append(balance).append(created);
        // 需要加密的字符串,       加密方式
        return CodecUtils.md5Hex(stringBuffer.toString(), Constants.BALANCE_SALT);
    }

    /**
     *  修改余额
     * @param userId  用户id
     * @param amount  当前用户余额
     * @param debit 本次操作为充值还是消费
     * @param orderNo 订单编号
     * @return
     */
    private Balance updateBalance(Long userId, BigDecimal amount, Integer debit, String orderNo){
        // 根据用户id 查询当前人的余额信息
        Balance balance = getById(userId);
        
        // 进行结果校验  那我们在数据库中到的记录的最后一条信息和传过来的用户进行校验, 断言一致,如果不一致那不就是数据篡改了
        Asserts.isTrue(checkOut(balance, userId), Constants.User.BALANCE_INFO_ERROR);

        BigDecimal amounts = balance.getAmounts();
        // 添加交易明细
        BalanceTrade balanceTrade = addTransactionDetail(userId, amount, debit, orderNo);
        BigDecimal subtract = amounts.subtract(amount);
        balanceTrade.setBalance(subtract);
        // 创建交易明细
        balanceTradeService.save(balanceTrade);
        // 修改余额
        balance.setAmounts(subtract);

        // 修改余额
        updateById(balance);

        return balance;
    }

    /**
     *
     * @param balance
     * @param userId
     * @return
     */
    //TODO
    private boolean checkOut(Balance balance, Long userId) {

        // 当前纪录人的最后一条信息
        BalanceTrade balanceTrade = balanceTradeService.getLastRecord(userId);
        // 按照当前查询到的数据进行加密,我们已经写好了加密方法,调用就好
        String checkCode = getCheckCode(balanceTrade.getOrderNo(), balanceTrade.getDebit(), balanceTrade.getAmount(), balanceTrade.getBalance(), balanceTrade.getCreated());

        // 用传过来的用户的加密字段和我们查询到的当前用户最后一次的记录, 按照我们自己的方式再一次加密得到的数据进行比较.
        return checkCode.equals(balance.getChecksum());
    }

    private BalanceTrade addTransactionDetail(Long userId, BigDecimal amount, Integer debit, String orderNo){
        // 构建交易明细对象
        BalanceTrade balanceTrade = BalanceTrade.of();
        // 往进塞值
        balanceTrade.setUserId(userId);
        balanceTrade.setAmount(amount);
        balanceTrade.setDebit(debit);
        balanceTrade.setOrderNo(orderNo);

        balanceTrade.setCreated(new Date());
        return balanceTrade;
    }

}
